#pragma once 

#include <iostream>
#include <ctime>
#include <unistd.h>
#include <vector>
#include <cstdlib>

#define NUM 8

template<typename T>
class RingQueue{
  private:
    std::vector<T> q;
    int capacity;
    int c_pos = 0;
    int p_pos = 0;
    pthread_mutex_t lock;
    pthread_cond_t full;
    pthread_cond_t empty;
  private:
    bool IsFull()
    {
      return abs(p_pos - c_pos) == capacity - 1;
    }
    bool IsEmpty()
    {
      return abs(p_pos - c_pos) == 0;
    }
  public:
    RingQueue(int _capacity = NUM):capacity(_capacity)
    {
      pthread_mutex_init(&lock, nullptr);
      pthread_cond_init(&full, nullptr);
      pthread_cond_init(&empty, nullptr);
      q.resize(_capacity);
    }
    void Push(const T& in)
    {
      pthread_mutex_lock(&lock);
      while(IsFull()){
        //等待
        pthread_cond_wait(&full, &lock);
      }

      q[c_pos++] = in;
      c_pos %= NUM;
      if(abs(c_pos - p_pos) > capacity / 2){
        pthread_cond_signal(&empty);
      }
      pthread_mutex_unlock(&lock);
      usleep(10);
    }
    void Pop(T& out)
    {
      pthread_mutex_lock(&lock);
      while(IsEmpty()){
        //等待
        pthread_cond_wait(&empty, &lock);
      }
      out = q[p_pos++];
      p_pos %= NUM;
      if(abs(p_pos - c_pos) <= capacity / 2){
        pthread_cond_signal(&full);
      }
      pthread_mutex_unlock(&lock);
      usleep(10);
    }
    ~RingQueue()
    {
      pthread_mutex_destroy(&lock);
      pthread_cond_destroy(&full);
      pthread_cond_destroy(&empty);
    }
};
